package com.sc.nft.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sc.nft.annotation.AuthenticationReadFile;
import com.sc.nft.annotation.UserLogin;
import com.sc.nft.controller.request.*;
import com.sc.nft.dao.DigitalCollectionDao;
import com.sc.nft.dao.ExitConsensusUserDao;
import com.sc.nft.dao.StaticDataDao;
import com.sc.nft.dto.EcologyHatchConfDao;
import com.sc.nft.entity.DigitalCollection;
import com.sc.nft.entity.EcologyHatchConf;
import com.sc.nft.entity.ExitConsensusUser;
import com.sc.nft.entity.StaticData;
import com.sc.nft.entity.dto.FlowRecordDTO;
import com.sc.nft.entity.vo.*;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.exception.GlobalException;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.pool.UserPool;
import com.sc.nft.service.OrderService;
import com.sc.nft.service.RoughStoneOrderService;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.PageResult;
import com.sc.nft.sup.Result;
import com.sc.nft.wrapper.RequestWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 服务控制器
 *
 * @author 张翔宇
 * @since 2022-06-02 01:07:23
 */
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/order")
@Api(tags = "订单")
public class OrderController {

    private final OrderService orderService;
    private final RoughStoneOrderService roughStoneOrderService;
    private final Redisson redisson;
    private final RedisTemplate redisTemplate;
    private final StaticDataDao staticDataDao;
    private final DigitalCollectionDao digitalCollectionDao;
    private final ExitConsensusUserDao exitConsensusUserDao;

    @ApiOperation(value = "根据订单号查询订单信息", notes = "根据订单号查询订单信息", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/findOrderByOrderNo", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<CreateOrderVO> findOrderByOrderNo(@Valid @RequestBody GetAliPayStatusByOrderNo request) throws GlobalException {
        return Result.success(orderService.findOrderByOrderNo(request.getOrderNo()));
    }

    @ApiOperation(value = "创建订单", notes = "创建订单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/createOrder", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<CreateOrderVO> createOrder(@Valid @RequestBody CreateOrderRequest request) throws GlobalException {
        String preOrderKey = RedisKeyEnum.PRE_ORDER.getKey() + UserPool.getUser().getId();
        Object o = redisTemplate.opsForValue().get(preOrderKey);
        if (ObjectUtil.isNull(o) || !StrUtil.equals(request.getProductId().toString(), (String) o)) {
            return Result.fail("当前人数过多，请稍后再试");
        }
        redisTemplate.delete(preOrderKey);
        CreateOrderVO order = null;
        RLock lock = redisson.getLock(RedisKeyEnum.STOCK_LOCK.getKey() + request.getProductId());
        try {
            boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {
                order = orderService.createOrder(request.getProductId(), request.getCount(), request.getFirstPayDTOs(), request.getRushBuyDTOs());
            }else {
                return Result.fail(ErrorCode.LATER_TRY);
            }
        } catch (InterruptedException e) {
            return Result.fail("当前人数过多，请稍后再试");
        } finally {
            lock.unlock();
        }
        return Result.success(order);
    }


    @ApiOperation(value = "领取免费藏品", notes = "领取免费藏品", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/receiveFreeCollection", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result receiveFreeCollection(@Valid @RequestBody CountRequest request) throws GlobalException {
        orderService.receiveFreeCollection(UserPool.getUser(),request.getId(),request.getCount());
        return Result.success( );
    }


    @ApiOperation(value = "预创建订单", notes = "预创建订单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/preCreateOrder", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result preCreateOrder(@Valid @RequestBody IdRequest request) throws GlobalException {
        StaticData byType = staticDataDao.getByType("black_list");
        if (BeanUtil.isNotEmpty(byType)) {
            String value = byType.getValue();
            if (StrUtil.isNotBlank(value)) {
                List<Long> list = JSONObject.parseArray(value, Long.class);
                if (list.contains(UserPool.getUser().getId())) {
                    return Result.success();
                }
            }
        }
        redisTemplate.opsForValue().set(RedisKeyEnum.PRE_ORDER.getKey() + UserPool.getUser().getId(), request.getId().toString(), 3, TimeUnit.SECONDS);
        return Result.success(true);
    }

    public final List<String> list = Lists.newArrayList("rushBuyDTOs", "firstPayDTOs");

    private Map requiredParameter(Object o) {
        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(o);
        Map<String, Object> paramMap = new TreeMap<>();
        // 遍历参数数组，将参数写入Map中
        stringObjectMap.forEach((s, o1) -> {
            if (list.contains(s)) {
                return;
            }
            if (o1 instanceof Collection) {
                // 把集合从小到大排序
                Collections.sort((List) o1);
            }
            paramMap.put(s, o1);
        });
        return paramMap;
    }

    @ApiOperation(value = "关闭订单", notes = "关闭订单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/closeOrder", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result closeOrder(@Valid @RequestBody IdRequest request) throws GlobalException {
        orderService.closeOrder(request.getId());
        return Result.success();
    }


    @ApiOperation(value = "订单列表", notes = "订单列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/page", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public PageResult page(@Valid @RequestBody OrderPageRequest request) throws GlobalException {
        return PageResult.success(orderService.orderPage(request.getOrderStatus(), request.getOrderType(), request.getPageNo(), request.getPageSize()));
    }

    @ApiOperation(value = "获取订单详情", notes = "获取订单详情", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getOrderDetailsById", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result page(@Valid @RequestBody IdRequest request) throws GlobalException {
        return Result.success(orderService.getOrderDetailsById(request.getId()));
    }


    @ApiOperation(value = "根据订单号获取订单状态", notes = "根据订单号获取订单状态")
    @PostMapping(value = "/getAliPayStatusByOrderNo", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    public Result getAliPayStatusByOrderNo(@Valid @RequestBody GetAliPayStatusByOrderNo request) {
        return orderService.getAliPayStatusByOrderNo(request.getOrderNo());
    }

    @ApiOperation(value = "根据商品id份数返回价格", notes = "根据商品id份数返回价格", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getTotalPrice", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin(required = false)
    public Result<GetTotalPriceVO> getTotalPrice(@Valid @RequestBody GetTotalPriceRequest request) {
        return Result.success(orderService.getTotalPrice(request.getProductId(), request.getProductCount()));
    }

    @ApiOperation(value = "成交趋势", notes = "成交趋势", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/tradingTrend", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<TradingTrendVO> tradingTrend(@Valid @RequestBody IdRequest idRequest) {
        DigitalCollection digitalCollection = digitalCollectionDao.getEcologyCollectionById(idRequest.getId());
        if(ObjectUtil.isNotNull(digitalCollection)){
            ExitConsensusUser exitConsensusUser = exitConsensusUserDao.getByUserId(UserPool.getUser().getId());
            if(ObjectUtil.isNotNull(exitConsensusUser)&&exitConsensusUser.getStatus()){
                return Result.success(orderService.tradingTrendNotInConsensus(idRequest.getId()));
            }else{
                return Result.success(orderService.tradingTrendForConsensus(idRequest.getId()));
            }
        }else{
            return Result.success(orderService.tradingTrend(idRequest.getId()));
        }
    }
    @ApiOperation(value = "流转记录", notes = "流转记录", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/flowRecord", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public PageResult<FlowRecordVO> flowRecord(@Valid @RequestBody FlowRecordDTO flowRecordDTO) {
        DigitalCollection digitalCollection = digitalCollectionDao.getEcologyCollectionById(flowRecordDTO.getCollectionId());
        if(ObjectUtil.isNotNull(digitalCollection)){
            ExitConsensusUser exitConsensusUser = exitConsensusUserDao.getByUserId(UserPool.getUser().getId());
            if(ObjectUtil.isNotNull(exitConsensusUser)&&exitConsensusUser.getStatus()){
                return PageResult.success(orderService.flowRecordNotInConsensus(flowRecordDTO));
            }else{
                return PageResult.success(orderService.flowRecordForConsensus(flowRecordDTO));
            }
        }else{
            return PageResult.success(orderService.flowRecord(flowRecordDTO));
        }

     }


    /**
     * 解析回调参数
     *
     * @param params
     * @return
     */
    public Map<String, String> analyticalParameters(String params) {
        if (StrUtil.isNotBlank(params)) {
            Map<String, String> paramsMap = Maps.newHashMap();
            for (String str : params.split("&")) {
                String[] s = str.split("=");
                if (s.length == 2) {
                    paramsMap.put(s[0], s[1]);
                } else {
                    paramsMap.put(s[0], StrUtil.EMPTY);
                }
            }
            return paramsMap;
        }
        return null;
    }

    @ApiOperation(value = "创建原石订单", notes = "创建原石订单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/createRoughStoneOrder", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<CreateOrderVO> createRoughStoneOrder(@Valid @RequestBody CreateRoughStoneOrderRequest request) throws GlobalException {
        CreateOrderVO order = null;
        RLock lock = redisson.getLock(RedisKeyEnum.STOCK_LOCK.getKey() + request.getProductId());
        try {
            boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (res) {
                order = orderService.createRoughStoneOrder(UserPool.getUser(), request.getProductId(), request.getCount());
            }else {
                return Result.fail(ErrorCode.LATER_TRY);
            }
        } catch (InterruptedException e) {
            return Result.fail("当前人数过多，请稍后再试");
        } finally {
            lock.unlock();
        }
        return Result.success(order);
    }

    @ApiOperation(value = "原石订单列表", notes = "原石订单列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/roughStonePage", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public PageResult roughStonePage(@Valid @RequestBody OrderPageRequest request) throws GlobalException {
        return PageResult.success(roughStoneOrderService.orderPage(UserPool.getUser(), request.getOrderStatus(), request.getPageNo(), request.getPageSize()));
    }


    @ApiOperation(value = "根据订单号查询订单信息(原石)", notes = "根据订单号查询订单信息(原石)", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/findRoughStoneOrderByOrderNo", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<CreateOrderVO> findRoughStoneOrderByOrderNo(@Valid @RequestBody GetAliPayStatusByOrderNo request) throws GlobalException {
        return Result.success(roughStoneOrderService.findRoughStoneOrderByOrderNo(request.getOrderNo()));
    }

    @ApiOperation(value = "关闭订单(原石)", notes = "关闭订单(原石)", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/closeRoughStoneOrder", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result closeRoughStoneOrder(@Valid @RequestBody IdRequest request) throws GlobalException {
        roughStoneOrderService.closeOrder(request.getId());
        return Result.success();
    }

    @ApiOperation(value = "获取订单详情(原石)", notes = "获取订单详情(原石)", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getRoughStoneOrderDetailsById", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<OrderDetailsVO> getRoughStoneOrderDetailsById(@Valid @RequestBody IdRequest request) throws GlobalException {
        return Result.success(roughStoneOrderService.getRoughStoneOrderDetailsById(request.getId()));
    }

}